package com.aigao.golf.common.config

import com.aigao.golf.common.shiro.DefaultModularRealm
import com.aigao.golf.common.shiro.MyUPToken
import com.aigao.golf.common.shiro.ShiroRealmPwd
import com.aigao.golf.common.shiro.ShiroWebSessionManager
import org.apache.shiro.authc.credential.HashedCredentialsMatcher
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy
import org.apache.shiro.cache.MemoryConstrainedCacheManager
import org.apache.shiro.codec.Base64
import org.apache.shiro.realm.Realm
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator
import org.apache.shiro.spring.LifecycleBeanPostProcessor
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor
import org.apache.shiro.spring.web.ShiroFilterFactoryBean
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter
import org.apache.shiro.web.mgt.CookieRememberMeManager
import org.apache.shiro.web.mgt.DefaultWebSecurityManager
import org.apache.shiro.web.servlet.SimpleCookie
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.DependsOn

/**
 * shiro配置
 */
@Configuration
class ShiroConfig {

    @Bean(name = ["cacheManager"])
    fun cacheManager() = MemoryConstrainedCacheManager()

    @Bean(name = ["cachingSessionDAO"])
    fun cachingSessionDAO(@Qualifier("cacheManager") cacheManager: MemoryConstrainedCacheManager): EnterpriseCacheSessionDAO{
        val cacheSessionDao = EnterpriseCacheSessionDAO()
        cacheSessionDao.cacheManager = cacheManager
        cacheSessionDao.sessionIdGenerator = JavaUuidSessionIdGenerator()
        return cacheSessionDao
    }


    @Bean(name = ["sessionManager"])
    fun sessionManager(@Qualifier("cachingSessionDAO") cachingSessionDAO: EnterpriseCacheSessionDAO): ShiroWebSessionManager {
        val webSessionManager = ShiroWebSessionManager()
        webSessionManager.sessionDAO = cachingSessionDAO
        webSessionManager.sessionValidationInterval = 1800000
        webSessionManager.globalSessionTimeout = 1800000
        webSessionManager.isDeleteInvalidSessions = true
        webSessionManager.sessionIdCookie.name = "tokenId"
        webSessionManager.sessionIdCookie.path = "/"
        return webSessionManager
    }


    @Bean(name = ["shiroRealmPwd"])
    fun shiroRealmPwd():ShiroRealmPwd {
        val realm = ShiroRealmPwd()
        return realm
    }


    @Bean(name = ["defineModularRealmAuthenticator"])
    fun defineModularRealmAuthenticator(@Qualifier("shiroRealmPwd")shiroRealmPwd : ShiroRealmPwd): DefaultModularRealm{
        val realm = DefaultModularRealm()
        val realms: MutableMap<Int, Realm> = HashMap()
        realms.put(MyUPToken.MK_LITE_APP,shiroRealmPwd)
        realms.put(MyUPToken.GL_WEB,shiroRealmPwd)
        realm.setRealms(realms)
        realm.authenticationStrategy = FirstSuccessfulStrategy()
        return realm
    }


    @Bean(name = ["sessionIdCookie"])
    fun sessionIdCookie() : SimpleCookie {
        val cookie = SimpleCookie("sid")
        cookie.isHttpOnly = true
        cookie.maxAge = -1
        return cookie
    }

    @Bean(name = ["remeberMeCookie"])
    fun remeberMeCookie():SimpleCookie{
        val cookie = SimpleCookie("rememberMe")
        cookie.isHttpOnly = true
        cookie.maxAge = 2592000
        return cookie
    }


    @Bean(name = ["remeberMeManager"])
    fun remeberMeManager(@Qualifier("remeberMeCookie")remeberMeCookie: SimpleCookie) : CookieRememberMeManager{
        val remember = CookieRememberMeManager()
        remember.cipherKey = Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")
        remember.cookie = remeberMeCookie
        return remember
    }
    
    
    @Bean(name = ["securityManager"])
    fun securityManager(@Qualifier("defineModularRealmAuthenticator") defineModularRealmAuthenticator:DefaultModularRealm,
                        @Qualifier("cacheManager") cacheManager: MemoryConstrainedCacheManager,
                        @Qualifier("sessionManager")sessionManager:ShiroWebSessionManager,
                        @Qualifier("shiroRealmPwd")shiroRealmPwd:ShiroRealmPwd,
                        @Qualifier("remeberMeManager")remeberMeManager:CookieRememberMeManager): DefaultWebSecurityManager{
        val securityManager = DefaultWebSecurityManager()
        securityManager.authenticator = defineModularRealmAuthenticator
        securityManager.cacheManager = cacheManager
        securityManager.sessionManager = sessionManager
        securityManager.rememberMeManager = remeberMeManager
        securityManager.setRealm(shiroRealmPwd)

        return securityManager
    }
    
    @Bean(name = ["formAuthenticationFilter"])
    fun formAuthenticationFilter() : FormAuthenticationFilter{
        val formFilter = FormAuthenticationFilter()
        formFilter.rememberMeParam = "rememberMe"
        return formFilter
    }


    @Bean(name = ["shiroFilter"])
    fun shiroFilter(@Qualifier("securityManager")securityManager:DefaultWebSecurityManager):ShiroFilterFactoryBean{
        val shiroFilter = ShiroFilterFactoryBean()
        shiroFilter.securityManager = securityManager
        shiroFilter.filterChainDefinitionMap = mapOf(
                "/app/customer/login" to "anon",
                "/managerment/user/login" to "anon",
                "/**" to "user"
        )
        return shiroFilter
    }


    @Bean(name = ["lifecycleBeanPostProcessor"])
    fun lifecycleBeanPostProcessor() = LifecycleBeanPostProcessor()


    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    fun defaultAdvisorAutoProxyCreator(): DefaultAdvisorAutoProxyCreator {
        val proxyCreater = DefaultAdvisorAutoProxyCreator()
        proxyCreater.isProxyTargetClass = true
        return proxyCreater
    }


    @Bean
    fun authorizationAttributeSourceAdvisor(@Qualifier("securityManager") securityManager: DefaultWebSecurityManager)
            :AuthorizationAttributeSourceAdvisor{
        val auth = AuthorizationAttributeSourceAdvisor()
        auth.securityManager = securityManager
        return auth
    }

}
